/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.msu.client.register;

import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.Service;
import io.iec.edp.caf.common.JSONSerializer;
import io.iec.edp.caf.commons.runtime.CafEnvironment;
import io.iec.edp.caf.msu.api.ServiceUnitAwareService;
import io.iec.edp.caf.msu.api.client.ServiceRegistry;
import io.iec.edp.caf.msu.api.entity.MsuConstVariable;
import io.iec.edp.caf.msu.api.entity.MsuProperties;
import io.iec.edp.caf.msu.api.entity.ServiceUnitInfo;
import io.iec.edp.caf.msu.api.entity.ServiceUnitRegisterInfo;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.PreDestroy;
import java.util.List;

import static io.iec.edp.caf.msu.api.entity.MsuConstVariable.CAF_NACOS_INSTANCE_CLUSTERNAME;

/**
 * 服务中心-服务注册（Nacos版）
 *
 * @author Leon Huo
 */
@Slf4j
public class NacosRegisterImpl implements ServiceRegistry {

    private NamingService namingService;
    private MsuProperties configuration;
    private ServiceUnitAwareService suAware;

    public NacosRegisterImpl(NamingService namingService, MsuProperties configuration, ServiceUnitAwareService suAware) {
        this.namingService = namingService;
        this.configuration = configuration;
        this.suAware = suAware;
    }

    @Override
    public Boolean register(ServiceUnitRegisterInfo registerInfo) {
        //注册
        register(registerInfo, CafEnvironment.getLocalIp(configuration.getIp().getPrefix()), CafEnvironment.getPort());

        return true;
    }

    @Override
    @PreDestroy
    public Boolean unRegister() {
        //组装信息并注销微服务
        ServiceUnitRegisterInfo unRegisterInfo = this.suAware.getServiceUnitRegisterInfo(configuration.getApplicationName(), configuration.getServiceName());
        doUnRegister(unRegisterInfo);

        return true;
    }

    @Override
    public Boolean register(ServiceUnitRegisterInfo registerInfo, String ip, Integer port) {
        doRegister(registerInfo, ip, port);
        return true;
    }

    private void doRegister(ServiceUnitRegisterInfo registerInfo, String ip, Integer port) {
        try {
            //namespace as application name
            String namespace = registerInfo.getAppName();

            //service name as deployment unit,
            //one su only belongs to one deployment unit.one deployment unit can has multiple copies.
            String serviceName = this.configuration.getServiceName();

            log.info("ServiceCenter(Nacos) Start to register su of group [{}]", namespace);

            List<ServiceUnitInfo> suList = registerInfo.getServiceUnitInfo();

            //循环注册su
            suList.forEach(x -> {
                try {

//                    Service service = new Service();
//                    service.setName(x.getName().toLowerCase());
//                    service.addMetadata(MsuConstVariable.MSU_BASEPATH,CafEnvironment.getBaseUrlPath());

                    x.setBasePath(CafEnvironment.getBaseUrlPath());
                    Instance instance = new Instance();
                    instance.setIp(ip);
                    instance.setPort(port);
                    instance.setWeight(1.0D);
                    instance.setClusterName(CAF_NACOS_INSTANCE_CLUSTERNAME);
                    instance.addMetadata(MsuConstVariable.CAF_NACOS_INSTANCE_METADATA, JSONSerializer.serialize(x));      //依托metadata存储微服务信息

                    this.namingService.registerInstance(x.getName().toLowerCase(), namespace, instance);
                    log.info("ServiceCenter(Nacos) Success to register su [{}]", x.getName().toLowerCase());
                } catch (NacosException e) {
                    log.error("ServiceCenter(Nacos) Failed to register su [{}], Error is {}", x.getName().toLowerCase(), e.getMessage(), e);
                }
            });

            log.info("ServiceCenter(Nacos) Finish register su");
        } catch (Throwable e) {
            throw new RuntimeException("Failed to register su to nacos : " + e.getMessage(), e);
        }
    }

    private void doUnRegister(ServiceUnitRegisterInfo unRegisterInfo) {
        try {
            //获取ip和port
            String namespace = unRegisterInfo.getAppName();

            log.info("ServiceCenter(Nacos) Start to unregister su of group [{}]", namespace);

            String ip = CafEnvironment.getLocalIp(configuration.getIp().getPrefix());
            Integer port = CafEnvironment.getPort();
            List<ServiceUnitInfo> suList = unRegisterInfo.getServiceUnitInfo();

            //循环注销su
            suList.forEach(x -> {
                try {
                    this.namingService.deregisterInstance(x.getName().toLowerCase(), namespace, ip, port, CAF_NACOS_INSTANCE_CLUSTERNAME);
                    log.info("ServiceCenter(Nacos) Success to unregister su [{}]", x.getName().toLowerCase());
                } catch (NacosException e) {
                    log.error("ServiceCenter(Nacos) Failed to unregister su [{}], Error is {}", x.getName().toLowerCase(), e.getMessage(), e);
                }
            });

            log.info("ServiceCenter(Nacos) Finish unregister su of group [{}]", namespace);
        } catch (Throwable e) {
            throw new RuntimeException("Failed to register su to nacos : " + e.getMessage(), e);
        }
    }

}
